#include <iostream>
#include <memory>
#include <string>

// 抽象产品类
class Computer
{
public:
    void SetBoard(const std::string &board)
    {
        _board = board;
    }
    void SetDisplay(const std::string &display)
    {
        _display = display;
    }
    virtual void SetOs() = 0;
    void ShowParama()
    {
        std::string param = "Computer Paramaters:\n";
        param += "\tBoard: " + _board + "\n";
        param += "\tDisplay: " + _display + "\n";
        param += "\tOS: " + _os + "\n";

        std::cout << param << std::endl;
    }

protected:
    std::string _board;
    std::string _display;
    std::string _os;
};
// 具体产品类
class MacBook : public Computer
{
public:
    virtual void SetOs() override
    {
        _os = "Mac OS x12";
    }
};


//建造者
// 抽象builder类：包含创建一个产品对象的各个部件的抽象接口
class Builder
{
public:
    virtual void buildBoard(const std::string &board) = 0;
    virtual void buildDisplay(const std::string &display) = 0;
    virtual void buildOS() = 0;
    virtual std::shared_ptr<Computer> build() = 0;
};
// 具有产品的builder类：实现抽象接口，构建和组装各个部件
class MacBookBuilder : public Builder
{
public:
    MacBookBuilder() : _computer(new MacBook()) {}
    virtual void buildBoard(const std::string &board)
    {
        _computer->SetBoard(board);
    }
    virtual void buildDisplay(const std::string &display)
    {
        _computer->SetDisplay(display);
    }
    virtual void buildOS()
    {
        _computer->SetOs();
    }
    virtual std::shared_ptr<Computer> build()
    {
        return _computer;
    }

private:
    std::shared_ptr<Computer> _computer;
};
//指挥者
// 指挥者Director类
//提供给调用者使用，通过指挥者来构造复杂产品
class Director//注意点1:指挥者不能继承建造者
{
public:
    Director(Builder* build) : _builder(build) {}
    void construct(const std::string &board, const std::string &display)
    {
        _builder->buildBoard(board);
        _builder->buildDisplay(display);
        _builder->buildOS();
    }

private:
    std::shared_ptr<Builder> _builder;
};

int main()
{
    Builder *builder = new MacBookBuilder();
    std::unique_ptr<Director> director(new Director(builder));
    director->construct("华硕主板", "三星显示器");

    std::shared_ptr<Computer> computer = builder->build();
    computer->ShowParama();

    return 0;
}